package br.com.management.mentor.app.listeners;

import java.nio.charset.Charset;
import java.util.Collection;
import java.util.List;
import java.util.Locale;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.Resource;

import br.com.management.mentor.app.Config;
import br.com.management.mentor.app.components.FilesResourceLocator;
import br.com.management.mentor.app.exceptions.AppStartUpException;
import br.com.management.mentor.app.listeners.persisters.EntityPersister;

import com.google.gson.Gson;

public class OnApplicationStartUpListener implements ApplicationListener<ContextStartedEvent> {

	private final Log logger = LogFactory.getLog( getClass() );

	@Autowired
	private EntityManagerFactory emf;

	@Autowired
	private List<EntityPersister<?>> entitiesPersistors;
	
	@Autowired
	private FilesResourceLocator fileResourceLocator;
	
	@Autowired
	private Locale defaultLocale;

	@Override
	public void onApplicationEvent( ContextStartedEvent event ) {
		ApplicationContext context = event.getApplicationContext();
		Configuration config = context.getBean( Configuration.class );
		
		setLocale();

		try {
			persistEntities( context , config );
		} catch ( Exception e ) {
			throw new AppStartUpException( new Object[]{ e.getMessage() } );
		}
	}

	private void setLocale() {
		Locale.setDefault( defaultLocale );
		LocaleContextHolder.setLocale( defaultLocale );
	}

	@SuppressWarnings( { "unchecked" , "rawtypes" } )
	private void persistEntities( ApplicationContext context , Configuration config ) {
		Gson gson = new Gson();
		Charset charset = Charset.forName( config.getString( Config.CHARSET.name() ) );

		for ( EntityPersister<?> ep : entitiesPersistors ) {

			String resourceURL = fileResourceLocator.getSourceFileURL( config.getString( ep.getResourcePath().name() ) );
			Resource resource = context.getResource( resourceURL );

			if ( resource.exists() ) {
				EntityManager em = emf.createEntityManager();
				em.setFlushMode( FlushModeType.COMMIT );

				try {
					String json = FileUtils.readFileToString( resource.getFile() , charset );
					Collection entities = gson.fromJson( json , ep.getEntityType() );

					if ( CollectionUtils.isEmpty( entities ) ) continue;

					em.getTransaction().begin();
					ep.persist( em , entities );
					em.getTransaction().commit();

				} catch ( Exception e ) {
					logger.error( "Error while persisting entities on application startup. Message: " + e.getMessage() );
					if ( em != null ) em.getTransaction().rollback();
				} finally {
					if ( em != null ) em.close();
				}
			}
		}

	}

	public List<EntityPersister<?>> getEntitiesPersistors() {
		return entitiesPersistors;
	}

	public void setEntitiesPersistors( List<EntityPersister<?>> entitiesPersistors ) {
		this.entitiesPersistors = entitiesPersistors;
	}

}